package showtime.framework.manager
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.media.Sound;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.system.SecurityDomain;
	import flash.utils.ByteArray;
	
	import showtime.framework.component.loading.GroupLoaderEvent;
	import showtime.framework.component.zip.ZipEntry;
	import showtime.framework.component.zip.ZipFile;
	import showtime.framework.core.pattern.Singleton;
	import showtime.framework.utils.StringUtility;
	
	
	/**
	 * This class to manager the resource read and write,such as swf, image(gif, png, gif).
	 * 
	 * @author yinhao
	 * 
	 */	
	public class AssetManager extends Singleton
	{
		/**
		 * SWF repository. 
		 */			
		private var swfMap:Object = null;
		/**
		 * TXT repository. 
		 */		
		private var xmlMap:Object = null;
		/**
		 * BMP repository. 
		 */		
		private var bmpMap:Object = null;
		/**
		 * OBJ repository. 
		 */		
		private var objMap:Object = null;
		/**
		 * Music repository. 
		 */		
		private var musicMap:Object = null;
	
		private var nowAmount:uint = 0;
		
		private var allAmount:int = 0;
		
		public var callback:Function = null;
		
		static public function getInstance():AssetManager
		{
			return AssetManager(Singleton.getInstanceOrCreate(AssetManager));
			
		}
		public function AssetManager()
		{
			super();
		}
		/**
		 * Pre initialize. 
		 * 
		 */		
		override protected function initialize():void
		{
			super.initialize();
			
			swfMap = {};
			
			xmlMap = {};
			
			bmpMap = {};
			
			objMap = {};
			
			musicMap = {};
			
		}
		/**
		 * Load resource as the path ,which you config in the xml. 
		 * @param key
		 * @param path
		 * 
		 */		
		private function load(key:String, path:String):void
		{
			key ||= filePathToFileName(path);
			
			allAmount++;
			
			switch (filePathToFileExt(path).toLocaleLowerCase())
			{
				// Load swf. 
				case "swf":
				{										
					/**
					 * SWF loader. 
					 */		
					var swfLoader:Loader = new Loader();
					
					swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoadCompleteHandler);
					swfLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
					swfLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
					// Jugde is http protocol.
					if (StringUtility.isHTTP(path))
					{						
						swfLoader.load(new URLRequest(path), new LoaderContext(false,  ApplicationDomain.currentDomain, SecurityDomain.currentDomain));
					}
					else
					{
						swfLoader.load(new URLRequest(path), new LoaderContext(false, ApplicationDomain.currentDomain));	
					}
					
					
					break;
				}
				// Load bmp..
				case "jpg":
				case "png":
				case "gif":
				{
					
					/**
					 * BMP loader. 
					 */		
					var bmpLoader:Loader = new Loader();
					
					bmpLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, bmpLoadCompleteHandler);
					bmpLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
					bmpLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
					bmpLoader.load(new URLRequest(path));
					
					break;
				}
					// Load xml.
				case "xml":
				{
					/**
					 * TXT loader. 
					 */		
					var xmlLoader:URLLoader = new URLLoader();
					
					xmlLoader.addEventListener(Event.COMPLETE, xmlLoadCompleteHandler);
					xmlLoader.addEventListener(ProgressEvent.PROGRESS, progressHandler);
					xmlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
					
					xmlLoader.load(new URLRequest(path));
					break;
				}
					// Load mp3.
				case "mp3":
				{
					var musicLoader:Sound = new Sound();
					
					musicLoader.addEventListener(Event.COMPLETE, musicLoaderCompleteHandler);
					musicLoader.addEventListener(ProgressEvent.PROGRESS, progressHandler);
					musicLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
					musicLoader.load(new URLRequest(path));
					
					break;
				}
					// Default error.
				default:
				{
					throw new Error("[AssetManager failed] - load unsupport mine data error.");
					break;
				}					
					
			}
			
			// Inner recall function.			
			function musicLoaderCompleteHandler(evt:Event):void
			{
				musicMap[key] = evt.target;
				
				nowAmount++;
				
				evt.target.removeEventListener(Event.COMPLETE, musicLoaderCompleteHandler);
				evt.target.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
				evt.target.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
				
				if (allAmount == nowAmount && callback != null)
				{
					trace("[Asset Manager] - resource load complete.");
					
					callback.call();
				}
			}
			
			function swfLoadCompleteHandler(evt:Event):void
			{
				swfMap[key] = evt.target.content;
				
				nowAmount++;
		
				evt.target.removeEventListener(Event.COMPLETE, swfLoadCompleteHandler);
				evt.target.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
				evt.target.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
				
				if (allAmount == nowAmount && callback != null)
				{
					trace("[Asset Manager] - resource load complete.");
					callback.call();
				}
			}
			
			function bmpLoadCompleteHandler(evt:Event):void
			{
				bmpMap[key] = Bitmap(evt.target.content).bitmapData;
				
				nowAmount++;
				
				evt.target.removeEventListener(Event.COMPLETE, bmpLoadCompleteHandler);
				evt.target.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
				evt.target.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
								
				if (allAmount == nowAmount && callback != null)
				{
					trace("[Asset Manager] - resource load complete.");	
					callback.call();
				}
			}
			
			function xmlLoadCompleteHandler(evt:Event):void
			{
				xmlMap[key] = XML(evt.target.data);
				
				nowAmount++;
				
				evt.target.removeEventListener(Event.COMPLETE, xmlLoadCompleteHandler);
				evt.target.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
				evt.target.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
				
				if (allAmount == nowAmount && callback != null)
				{
					trace("[Asset Manager] - resource load complete.");
					callback.call();
				}
			}
			
			function progressHandler(evt:ProgressEvent):void
			{				
				dispatchEvent(new GroupLoaderEvent(GroupLoaderEvent.PROGRESS, false, false, evt.bytesLoaded, evt.bytesTotal, nowAmount, allAmount));
			}
			
			function ioErrorHandler(evt:IOErrorEvent):void
			{
				trace("[Asset Manager] - resource load complete.");
			}
		}
		
		public function loadFromZip(stream:ByteArray):void
		{
			var zip:ZipFile = new ZipFile(stream);
			var nowAmount:int = 0;
			for(var index:int = 0; index < zip.entries.length; index++) 
			{
				var entry:ZipEntry = zip.entries[index];
				var data:ByteArray = zip.getInput(entry);
				
				switch (filePathToFileExt(entry.name).toLocaleLowerCase())
				{
					case "jpg":
					case "png":
					{
						var _loader : Loader = new Loader();
						_loader.name = entry.name.split("/").reverse()[0].split(".")[0];
						_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(event:Event):void{nowAmount++;  nowAmount == zip.size && dispatchEvent(new GroupLoaderEvent(GroupLoaderEvent.COMPLETE));event.currentTarget.removeEventListener(Event.COMPLETE, arguments.callee);bmpMap[event.target.loader.name] = event.target.loader.content.bitmapData;});				
						_loader.loadBytes(data);
						break;
					}
					case "xml":
					{
						nowAmount++;
						break;
					}
					default:
					{
						nowAmount++;
					}
				}				
			}	

		}
		/**
		 * 
		 * Load resource path from xml. 
		 * @param path
		 * 
		 */		
		public function loadFromXML(path:String):void
		{
			var urlLoader:URLLoader = new URLLoader();
			urlLoader.load(new URLRequest(path));
			
			urlLoader.addEventListener(Event.COMPLETE, loadCompleteHandler);
			
			function loadCompleteHandler(event:Event):void
			{
				urlLoader.removeEventListener(Event.COMPLETE, loadCompleteHandler);
				// Analysis xml data.
				xmlAnalysis(new XML(urlLoader.data));
			}
		}
		
		/**
		 * 
		 * To analysis xml file.
		 * 
		 * @param xml
		 * @example
		 * 
		 * <xml>
		 * 		<file key="delphi" path="delphi.swf" />
		 * 		<file path="delphi.jpg" />
		 * 		<file path="abc.txt" />
		 * </xml>
		 */				
		private function xmlAnalysis(xml:XML):void
		{
			if (xml.hasOwnProperty("file"))
			{
				for each (var element:XML in xml.file)
				{
					var path:String = element.@path;
					var key:String = element.@key;
					load(key, path);
				}
			}
			else
			{
				callback.call();
			}
		}
		
		/**
		 * Get file name.
		 * 
		 * @param path
		 * @return 
		 * 
		 */			
		private function filePathToFileName(path:String):String
		{
			path = path.slice(path.lastIndexOf("/") + 1);
			path = path.slice(0, path.indexOf("."));
			
			return path;
		}
		
		/**
		 * Get file ext name. 
		 * @param path
		 * @return 
		 * 
		 */		
		private function filePathToFileExt(path:String):String
		{
			path = path.slice(path.lastIndexOf(".") + 1);
			
			return path;
		}
		
		
		
		public function cacheAsOBJ(key:String, data:Object):void
		{
			objMap[key] = data;
		}

		public function getOBJ(key:String):Object
		{
			if (objMap.hasOwnProperty(key))
			{
				return objMap[key];	
			}
			
			return null;				
		}
		
		public function removeOBJ(key:String):void
		{
			if (objMap.hasOwnProperty(key))
			{
				delete objMap[key];	
			}
			
		}
		/**
		 * Get xml resource. 
		 * @param key
		 * @return 
		 * 
		 */		
		public function getXML(key:String):XML
		{
			return XML(xmlMap[key]);
		}
		
		
		/**
		 *Get Bitmap object.  
		 * @param key
		 * @return 
		 * 
		 */		
		public function getBMP(key:String):BitmapData
		{
			return bmpMap[key] as BitmapData;
		}
		
		/**
		 * Get Bitmap data object. 
		 * @return 
		 * 
		 */		
		public function getGraphic(key:String):BitmapData
		{		
			var Clazz:Class = getClass(key);

			return new Clazz(0, 0) as BitmapData;
		}
		
		public function getMP3(key:String):Sound
		{
			return musicMap[key];
		}
	
		
		public function getSWF(key:String):DisplayObject
		{
			return swfMap[key];
		}
		
		/**
		 * Get Class object.
		 * @return 
		 * 
		 */		
		public function getClass(key:String):Class
		{
			if (ApplicationDomain.currentDomain.hasDefinition(key))
			{
				return ApplicationDomain.currentDomain.getDefinition(key) as Class;
			}
			
			trace("[Asset Manager] - not Defination class By " + key );
			
			return null;	
		}
		
		public function getZIP(key:String):Object
		{
			return null;
		}
		
		/**
		 * Get byte array. 
		 * @param key
		 * @return 
		 * 
		 */		
		public function getByteArray(key:String):ByteArray
		{
			return null;
		}
		
	}
}